home *** CD-ROM | disk | FTP | other *** search
- /***********************************************************************
- *
- * PROJECT: PMake
- * MODULE: Prefix -- Prefix Importation
- * FILE: import.c
- *
- * AUTHOR: Adam de Boor: Jul 5, 1989
- *
- * ROUTINES:
- * Name Description
- * ---- -----------
- * Import_Init Initialize the module
- * Import_MountPrefix Mount a prefix on ourselves
- * Import_CreatePrefix Create and initialize a Prefix structure
- * FOR AN EXISTING DIRECTORY. Not suitable
- * for prefixes under a root.
- *
- * REVISION HISTORY:
- * Date Name Description
- * ---- ---- -----------
- * 7/ 5/89 ardeb Initial version
- *
- * DESCRIPTION:
- * Functions to deal with importing prefixes.
- *
- * A prefix appears to the kernel as if it were a read-only,
- * empty directory until the first LOOKUP operation is performed
- * on it. The LOOKUP operation is redirected, by claiming the
- * file in question is a symbolic link, to the MOUNT_DIR (the
- * exact destination is MOUNT_DIR/<prefix>.<generation>/<component>,
- * where <prefix> is the ascii representation of the address of the
- * Prefix structure, <generation> is the ascii representation of the
- * prefix's generation number, and <component> is the component being
- * sought).
- *
- * When the kernel does a LOOKUP operation in MOUNT_DIR, we
- * unmount the prefix and mount the real one, then redirect the
- * kernel back there again....
- *
- * NOTE: ANY fhandle_t RETURNED TO THE KERNEL SHOULD BE ZEROED
- * OUT BEFORE STORING THE VALUE IN IT, AS THE SUN
- * IMPLEMENTATION, AT LEAST, USES BYTES 1, 5 AND 15 FOR
- * HASHING.
- *
- * Copyright (c) Berkeley Softworks 1989
- * Copyright (c) Adam de Boor 1989
- *
- * Permission to use, copy, modify, and distribute this
- * software and its documentation for any non-commercial purpose
- * and without fee is hereby granted, provided that the above copyright
- * notice appears in all copies. Neither Berkeley Softworks nor
- * Adam de Boor makes any representations about the suitability of this
- * software for any purpose. It is provided "as is" without
- * express or implied warranty.
- *
- ***********************************************************************/
- #ifndef lint
- static char *rcsid =
- "$Id: import.c,v 1.16 89/10/10 00:32:09 adam Exp $";
- #endif lint
-
- #include "prefix.h"
- #include "rpc.h"
- #include "sunrpc.h"
-
- #include <arpa/inet.h>
- #include <netdb.h>
-
- static int prefixSvc; /* Socket for prefix NFS requests */
-
- /*
- * Token we allocate when given a LOOKUP operation on a prefix. Points
- * to the prefix involved as well as the name of the component that was
- * being looked up before we redirected the kernel to our mount directory.
- *
- * A LookupToken remains valid for 10 seconds after it is created, after
- * which it is deleted from the tokens list. Any later use of a handle with
- * the token's address in it will be rejected.
- *
- * When a token is deleted, it is placed on the freeTokens list to be
- * re-used later. Each token has a "generation number" that is simply
- * a counter that gets incremented each time the token is allocated. The
- * generation number of the token is returned in the fhandle and compared
- * when a readlink is performed to ensure the kernel's idea and our idea
- * of what is being looked up coincide. The generation number is set to
- * zero when the token is first allocated.
- *
- * Maintaining a pool of free tokens allows us to make sure that if the
- * kernel ever comes back with a lookup token, we won't be deceived into
- * doing something bad because the memory has been re-used and happens to
- * contain good values in the fields used for checking token validity.
- */
- typedef struct _LookupToken {
- Prefix *prefix; /* Prefix in which the name was looked up */
- char *name; /* Name that was sought */
- int generation; /* Generation number for this token */
- Rpc_Event nukeEvent; /* Event that will biff this token. Needed in
- * case the token must be nuked prematurely,
- * e.g. when a temporary prefix gets nixed */
- } LookupToken;
-
- static Lst tokens; /* List of active tokens */
- static Lst freeTokens; /* Pool of previously allocated tokens that
- * can be reused */
-
- #define IS_LOOKUP_HAN(f) (((PrefixHandle *)f)->type == PH_LOOKUP)
- #define IS_VALID_LH(f) \
- ((((PrefixHandle *)f)->ld.generation == \
- ((PrefixHandle *)f)->ld.ltp->generation) && \
- (Lst_Member(tokens, (ClientData)((PrefixHandle *)f)->ld.ltp) != NILLNODE))
-
- /*
- * Given a buffer and a LookupToken, place the path-via-MOUNT_DIR-for-
- * redirecting-the-kernel-("Look! A UFO!")-while-we-mount-the-real-FS into
- * the buffer.
- */
- #define LT_PATH(dest,ltp) sprintf(dest, "%s/%d.%d/%s", MOUNT_DIR, \
- ((LookupToken *)ltp)->prefix, \
- ((LookupToken *)ltp)->prefix->generation, \
- ((LookupToken *)ltp)->name)
-
- /*
- * Attributes returned for any symbolic link
- */
- struct nfsfattr link_attr = {
- NFLNK, /* na_type */
- 0777 | S_IFLNK, /* na_mode */
- 1, /* na_nlink */
- 0, /* na_uid */
- 0, /* na_gid */
- 0, /* na_size (filled in later) */
- 0, /* na_blocksize (filled in later) */
- -1, /* na_rdev (Garbage) */
- 1, /* na_blocks */
- -1, /* na_fsid (Garbage) */
- 16, /* na_nodeid (Garbage) */
- {0,0}, /* na_atime (Garbage) */
- {0,0}, /* na_mtime (Garbage) */
- {0,0}, /* na_ctime (Garbage) */
- };
-
- /* FORWARD DECL */
- static int ImportDeleteTemp();
- /******************************************************************************
- *
- * UTILITY ROUTINES
- *
- *****************************************************************************/
-
- /***********************************************************************
- * ImportTokenToHandle
- ***********************************************************************
- * SYNOPSIS: Convert a LookupToken into an NFS handle
- * CALLED BY: ImportLookupReq
- * RETURN: Nothing
- * SIDE EFFECTS: Handle is filled in.
- *
- * STRATEGY:
- *
- * REVISION HISTORY:
- * Name Date Description
- * ---- ---- -----------
- * ardeb 10/ 9/89 Initial Revision
- *
- ***********************************************************************/
- static void
- ImportTokenToHandle(ltp, fh)
- LookupToken *ltp;
- fhandle_t *fh;
- {
- PrefixHandle *lhp; /* Internal form */
-
- lhp = (PrefixHandle *)fh;
-
- /*
- * Make sure unused bytes are 0
- */
- bzero(fh, sizeof(*fh));
- /*
- * Set up significant fields.
- */
- lhp->ld.type = PH_LOOKUP;
- lhp->ld.generation = ltp->generation;
- lhp->ld.ltp = ltp;
- }
-
- /***********************************************************************
- * ImportDeleteLookupToken
- ***********************************************************************
- * SYNOPSIS: Nuke an expired LookupToken
- * CALLED BY: Rpc event, ImportDeleteTemp, ImportDelete
- * RETURN: FALSE (don't stay awake)
- * SIDE EFFECTS: The token's name is freed and the token itself is
- * shifted to the freeTokens list with its generation
- * number increased by one.
- *
- * STRATEGY:
- *
- * REVISION HISTORY:
- * Name Date Description
- * ---- ---- -----------
- * ardeb 7/ 5/89 Initial Revision
- *
- ***********************************************************************/
- static Boolean
- ImportDeleteLookupToken(ltp, ev)
- LookupToken *ltp; /* Token to nuke */
- Rpc_Event ev; /* Event that called us */
- {
- LstNode ln;
-
- /*
- * Locate and remove the token from the list of valid tokens.
- */
- ln = Lst_Member(tokens, (ClientData)ltp);
- Lst_Remove(tokens, ln);
-
- /*
- * Free its memory.
- */
- free(ltp->name);
-
- /*
- * Put it back in the pool, upping its generation number to make life
- * easier when checking (should very rarely have to do a Lst_Member).
- */
- ltp->generation += 1;
- (void)Lst_AtEnd(freeTokens, (ClientData)ltp);
-
- /*
- * Don't want to be called again...
- */
- Rpc_EventDelete(ev);
-
- /*
- * No need to stay awake on our account.
- */
- return(FALSE);
- }
-
- /***********************************************************************
- * ImportAllocLookupToken
- ***********************************************************************
- * SYNOPSIS: Allocate a new lookup token
- * CALLED BY: ImportLookupReq
- * RETURN: A token to use.
- * SIDE EFFECTS: A token will be removed from the freeTokens list,
- * if possible.
- *
- * STRATEGY:
- *
- * REVISION HISTORY:
- * Name Date Description
- * ---- ---- -----------
- * ardeb 10/ 9/89 Initial Revision
- *
- ***********************************************************************/
- static LookupToken *
- ImportAllocLookupToken()
- {
- LookupToken *ltp;
-
- if (!Lst_IsEmpty(freeTokens)) {
- ltp = (LookupToken *)Lst_DeQueue(freeTokens);
- } else {
- ltp = (LookupToken *)malloc(sizeof(LookupToken));
- ltp->generation = 0; /* First-generation */
- }
- return(ltp);
- }
-
- /***********************************************************************
- * ImportSetLinkAttr
- ***********************************************************************
- * SYNOPSIS: Setup returned attributes to be for a link to the
- * given path.
- * CALLED BY: ImportLookup, ImportGetAttr
- * RETURN: Nothing
- * SIDE EFFECTS:
- *
- * STRATEGY:
- *
- * REVISION HISTORY:
- * Name Date Description
- * ---- ---- -----------
- * ardeb 7/11/89 Initial Revision
- *
- ***********************************************************************/
- static void
- ImportSetLinkAttr(attrPtr, path, pp)
- struct nfsfattr *attrPtr; /* Place to store attributes */
- char *path; /* Destination of link */
- Prefix *pp; /* Prefix containing the link */
- {
- *attrPtr = link_attr;
-
- /*
- * Fill in specific fields that need filling (size,
- * in case kernel uses it for storage when doing the
- * read, and blocksize, for the hell of it).
- */
- attrPtr->na_size = strlen(path);
- attrPtr->na_blocksize = pp->attr.na_blocksize;
- }
- /******************************************************************************
- *
- * PREFIX LOCATION
- *
- *****************************************************************************/
-
- /***********************************************************************
- * ImportLocateResponse
- ***********************************************************************
- * SYNOPSIS: Handle response from our PREFIX_LOCATE broadcast
- * CALLED BY: Rpc
- * RETURN: 1 (stop broadcast)
- * SIDE EFFECTS: The server, serverName and remote fields of the
- * 'searching' prefix are filled in based on the
- * response.
- *
- * STRATEGY:
- * - Figure name of responder
- * - Write result to console
- * - Allocate room for and store the server and remote directory
- * - Record server's address
- *
- * REVISION HISTORY:
- * Name Date Description
- * ---- ---- -----------
- * ardeb 7/ 5/89 Initial Revision
- *
- ***********************************************************************/
- static Boolean
- ImportLocateResponse(from, len, data, searching)
- struct sockaddr_in *from; /* Source of response */
- int len; /* Size of return data buffer */
- Rpc_Opaque data; /* Data returned */
- Prefix *searching; /* Prefix for which we're searching */
- {
- struct hostent *he; /* Description of host to which 'from'
- * belongs */
- char *name; /* Name to use for server */
-
- /*
- * We'd like to put/print the host name, not just its address, so
- * try and convert from an address into a name, leaving the final
- * result pointed to by "name"
- */
- he = gethostbyaddr(&from->sin_addr,
- sizeof(from->sin_addr),
- AF_INET);
-
- if (he) {
- /*
- * Trim off any domain that's there...
- */
- name = (char *)index(he->h_name, '.');
- if (name != NULL) {
- *name = '\0';
- }
- name = he->h_name;
- } else {
- name = InetNtoA(from->sin_addr);
- }
-
- /*
- * Complete "Broadcasting for..." message.
- */
- if (!quiet) {
- Message("served by %s[%s]", name, data);
- }
-
- /*
- * Allocate room for the two strings we need to store
- */
- searching->serverName = (char *)malloc(strlen(name) + 1);
- searching->remote = (char *)malloc(strlen((char *)data) + 1);
-
- /*
- * Store the server data in the prefix entry
- */
- searching->server = *from;
- strcpy(searching->serverName, name);
- strcpy(searching->remote, (char *)data);
-
- /*
- * Stop broadcasting
- */
- return(1);
- }
-
- /***********************************************************************
- * ImportLocatePrefix
- ***********************************************************************
- * SYNOPSIS: Find the server for a prefix.
- * CALLED BY: ImportReadLink
- * RETURN: 1 if server found.
- * SIDE EFFECTS: The serverName, remote and server fields of the
- * prefix are filled in.
- *
- * STRATEGY:
- *
- * REVISION HISTORY:
- * Name Date Description
- * ---- ---- -----------
- * ardeb 7/11/89 Initial Revision
- *
- ***********************************************************************/
- static int
- ImportLocatePrefix(pp)
- Prefix *pp; /* Prefix to find */
- {
- struct sockaddr_in sin; /* INADDR_ANY for Rpc_Broadcast */
- struct timeval retry; /* Retrans interval */
- char path[NFS_MAXPATHLEN]; /* Buffer for remote path */
-
- if (pp->serverName == NULL) {
- /*
- * Broadcast to locate the server for the thing, now
- * we know the kernel really wants it...
- */
- if (!quiet) {
- Message("Broadcasting for server of \"%s\"...", pp->path);
- }
-
- /*
- * Let Rpc_Broadcast figure the net(s) to which to go,
- * but tell it what port to use...
- */
- sin.sin_family = AF_INET;
- sin.sin_port = htons(PREFIX_PORT);
- sin.sin_addr.s_addr = htonl(INADDR_ANY);
-
- /*
- * Retry every second
- */
- retry.tv_sec = 1;
- retry.tv_usec = 0;
-
- if (Rpc_Broadcast(prefixSock, &sin, PREFIX_LOCATE,
- strlen(pp->path)+1, pp->path,
- sizeof(path), path,
- 3, &retry,
- ImportLocateResponse, (Rpc_Opaque)pp)!=RPC_SUCCESS)
- {
- /*
- * No-one's got it -- return an error
- */
- if (!quiet) {
- Message("no-one's home.");
- }
- return(0);
- }
- }
- return(1);
- }
-
-
- /******************************************************************************
- *
- * SUN-RPC SERVERS
- *
- *****************************************************************************/
-
- /***********************************************************************
- * ImportNullReq
- ***********************************************************************
- * SYNOPSIS: Let the caller know we're alive
- * CALLED BY: RFS_NULL
- * RETURN: SUNRPC_SUCCESS
- * SIDE EFFECTS: None
- *
- * STRATEGY:
- *
- * REVISION HISTORY:
- * Name Date Description
- * ---- ---- -----------
- * ardeb 9/10/89 Initial Revision
- *
- ***********************************************************************/
- static enum clnt_stat
- ImportNullReq(remote, msg, args, res, data, resPtr)
- struct sockaddr_in *remote; /* Source of request */
- Rpc_Message msg; /* Message token */
- void *args; /* Arguments passed */
- void *res; /* Results to return */
- Rpc_Opaque data; /* Data we stored (UNUSED) */
- void **resPtr; /* Room for modified 'res' (UNUSED)*/
- {
- return(SUNRPC_SUCCESS);
- }
-
- /***********************************************************************
- * ImportGetAttrReq
- ***********************************************************************
- * SYNOPSIS: Fetch the attributes of a prefix.
- * CALLED BY: SunRpc
- * RETURN: SUNRPC_SUCCESS (any error code is in result)
- * SIDE EFFECTS: None
- *
- * STRATEGY:
- *
- * REVISION HISTORY:
- * Name Date Description
- * ---- ---- -----------
- * ardeb 7/11/89 Initial Revision
- *
- ***********************************************************************/
- static enum clnt_stat
- ImportGetAttrReq(remote, msg, args, res, data, resPtr)
- struct sockaddr_in *remote; /* Source of request */
- Rpc_Message msg; /* Message token */
- fhandle_t *args; /* Arguments passed */
- struct nfsattrstat *res; /* Results to return */
- Rpc_Opaque data; /* Data we stored (UNUSED) */
- void **resPtr; /* Room for modified 'res' (UNUSED)*/
- {
- Prefix *pp; /* Prefix to stat */
- char path[512]; /* Path for filling in result */
-
- if (!IS_LOOKUP_HAN(args)) {
- /*
- * Really a prefix -- convert to a Prefix and return
- * the stored attributes
- */
- pp = HandleToPrefix(args);
-
- if (pp == PREFIX_STALE) {
- res->ns_status = NFSERR_STALE;
- } else {
- dprintf("GETATTR(%s)\n", pp->path);
-
- /*
- * Install saved attributes
- */
- res->ns_status = NFS_OK;
- res->ns_attr = pp->attr;
- }
- } else {
- /*
- * This is here only for safety. I doubt it will
- * ever be called... WRONG! SunOS 4.0 calls this... I guess
- * because we tell it to cache no attributes...
- */
- PrefixHandle *lth = (PrefixHandle *)args;
-
- if (!IS_VALID_LH(args)) {
- res->ns_status = NFSERR_STALE;
- } else {
- LookupToken *ltp = lth->ld.ltp;
-
- dprintf("GETATTR(%s/%s)\n", ltp->prefix->path, ltp->name);
-
- /*
- * Form path so we return the proper size
- */
- LT_PATH(path, ltp);
-
- /*
- * Use default attributes for symbolic links.
- */
- res->ns_status = NFS_OK;
-
- ImportSetLinkAttr(&res->ns_attr, path, ltp->prefix);
- }
- }
- return(SUNRPC_SUCCESS);
- }
-
- /***********************************************************************
- * ImportReadLinkReq
- ***********************************************************************
- * SYNOPSIS: Read the value of one of our "links"
- * CALLED BY: SunRpc
- * RETURN: SUNRPC_SUCCESS (link contents returned to caller)
- * SIDE EFFECTS: The server for the prefix is sought and the
- * serverName, server and remote fields for it filled in.
- *
- * STRATEGY:
- *
- * REVISION HISTORY:
- * Name Date Description
- * ---- ---- -----------
- * ardeb 7/11/89 Initial Revision
- *
- ***********************************************************************/
- static enum clnt_stat
- ImportReadLinkReq(remote, msg, args, res, data, resPtr)
- struct sockaddr_in *remote; /* Source of request */
- Rpc_Message msg; /* Message token */
- fhandle_t *args; /* Arguments passed */
- struct nfsrdlnres *res; /* Results to return */
- Rpc_Opaque data; /* Data we stored (UNUSED) */
- void **resPtr; /* Room for modified 'res' (UNUSED)*/
- {
- Prefix *pp;
- char path[512]; /* Link's contents */
-
- /*
- * Convert the handle into a token.
- */
- if (IS_LOOKUP_HAN(args)) {
- if (!IS_VALID_LH(args)) {
- /*
- * Not in the active list -- must be stale
- */
- dprintf("READLINK -- stale handle\n");
- res->rl_status = NFSERR_STALE;
- } else {
- LookupToken *ltp; /* Token we created during LOOKUP */
-
- ltp = ((PrefixHandle *)args)->ld.ltp;
-
- /*
- * Make life easier by fetching out the prefix itself
- */
- pp = ltp->prefix;
-
- dprintf("READLINK(%s/%s)\n", pp->path, ltp->name);
-
- res->rl_status = NFS_OK;
-
- if (pp->serverName == NULL) {
- /*
- * We are not allowed to look for a prefix that is locked,
- * as doing so could result in our deleting the thing while
- * someone else is looking for it. The best way to handle
- * this is to force the kernel to resubmit its request when
- * we are more likely to be able to give it an answer. We
- * do this by instructing SunRpc to drop the request on the
- * floor.
- */
- if (PrefixIsLocked(pp)) {
- return(SUNRPC_DONTRESPOND);
- }
- PrefixLock(pp);
- if (!ImportLocatePrefix(pp)) {
- /*
- * If prefix is temporary and we were trying to locate
- * it, we can safely delete the thing if we can't find
- * its server. This will prevent repeated search for
- * something due to "getwd" (which does a readdir and
- * stat) when something gets into the prefix table
- * unintentionally.
- */
- PrefixUnlock(pp);
- if (pp->flags & PREFIX_TEMP) {
- (void)ImportDeleteTemp(pp);
- }
- res->rl_status = NFSERR_NOENT;
- } else {
- PrefixUnlock(pp);
- }
- } else {
- dprintf("served by %s[%s]\n", pp->serverName, pp->remote);
- }
-
- if (res->rl_status == NFS_OK) {
- /*
- * Return a path to the "file" in the mount directory
- * whose name is the ascii representation of the Prefix
- * structure's address, with the component being sought
- * just below that. The kernel should then perform a
- * LOOKUP operation in the mount directory, at which
- * time we should be able to unmount this thing and
- * mount the real one. The kernel will track the
- * extra component so we don't need to.
- */
- LT_PATH(path, ltp);
- dprintf("returning \"%s\"\n", path);
- /*
- * Set up return value at the end of the nfsrdlnres
- */
- res->rl_count = strlen(path);
- res = (struct nfsrdlnres *)realloc(res,
- sizeof(*res)+res->rl_count);
- *resPtr = (void *)res;
- res->rl_data = (char *)(res+1);
- bcopy(path, res->rl_data, res->rl_count);
- }
- }
- } else {
- /*
- * BOGUS -- should never happen
- */
- res->rl_status = NFSERR_STALE;
- }
- return(SUNRPC_SUCCESS);
- }
-
- /***********************************************************************
- * ImportCreateTempPrefix
- ***********************************************************************
- * SYNOPSIS: Create a new temporary prefix
- * CALLED BY: ImportLookupReq
- * RETURN: The Prefix * for the new prefix, linked into the
- * parent and the global list.
- * SIDE EFFECTS: All fields of the prefix are initialized.
- *
- * STRATEGY:
- *
- * REVISION HISTORY:
- * Name Date Description
- * ---- ---- -----------
- * ardeb 7/11/89 Initial Revision
- *
- ***********************************************************************/
- static Prefix *
- ImportCreateTempPrefix(path, pp)
- char *path; /* Path for the prefix */
- Prefix *pp; /* Parent prefix */
- {
- Prefix *newpp;
- Prefix *prev;
- Prefix *tp;
-
- newpp = AllocPrefix();
-
- newpp->path = (char *)malloc(strlen(path) + 1);
- strcpy(newpp->path, path);
-
- /*
- * Mark the prefix as temporary, so we don't remount the thing after
- * deleting it.
- */
- newpp->flags = PREFIX_TEMP;
- newpp->locks = 0;
-
- /*
- * The new prefix is a clone of the root prefix, except for the file
- * number...
- */
- newpp->options = pp->options;
- newpp->attr = pp->attr;
-
- /*
- * Need to use a different file number to keep the kernel from getting
- * confused.
- */
- if (pp->next) {
- newpp->attr.na_nodeid = pp->next->attr.na_nodeid + 1;
- } else {
- newpp->attr.na_nodeid = pp->attr.na_nodeid + 1;
- }
-
- /*
- * Clear out the rest of the fields
- */
- newpp->unmount = (Rpc_Event)NULL;
- newpp->serverName = newpp->remote = (char *)NULL;
-
- /*
- * Record it.
- */
- (void)Lst_AtEnd(prefixes, (ClientData)newpp);
-
- /*
- * Record it under its parent so we can deal with a READDIR on the parent
- * (to allow for file completion, mostly). We place it at the end of
- * the queue to try and avoid unnecessary mounts due to getwd() calls.
- */
- for (prev = pp, tp = pp->next; tp != NULL; prev = tp, tp = tp->next) {
- ;
- }
- prev->next = newpp;
- newpp->next = (Prefix *)NULL;
-
- return(newpp);
- }
-
- /***********************************************************************
- * ImportLookupReq
- ***********************************************************************
- * SYNOPSIS: Handle a LOOKUP operation in a prefix.
- * CALLED BY: SunRpc
- * RETURN: SUNRPC_SUCCESS (handle and attributes returned to caller)
- * SIDE EFFECTS: A LookupToken is created and saved
- *
- * STRATEGY:
- * The search of a prefix means its corresponding filesystem must
- * be mounted.
- *
- * REVISION HISTORY:
- * Name Date Description
- * ---- ---- -----------
- * ardeb 7/11/89 Initial Revision
- *
- ***********************************************************************/
- static enum clnt_stat
- ImportLookupReq(remote, msg, args, res, data, resPtr)
- struct sockaddr_in *remote; /* Source of request */
- Rpc_Message msg; /* Message token */
- struct nfsdiropargs *args; /* Arguments passed */
- struct nfsdiropres *res; /* Results to return */
- Rpc_Opaque data; /* Data we stored (UNUSED) */
- void **resPtr; /* Room for modified 'res' (UNUSED)*/
- {
- Prefix *pp; /* Prefix to import */
- LookupToken *ltp; /* New token for later READLINK */
- char path[512]; /* Contents of "link" (for setting
- * size in link's attributes) */
-
- pp = HandleToPrefix(&args->da_fhandle);
-
- if (pp == PREFIX_STALE) {
- res->dr_status = NFSERR_STALE;
- } else {
- dprintf("LOOKUP(%s:%s)\n", pp->path, args->da_name);
-
- if (args->da_name[0] == '.' &&
- (args->da_name[1] == '\0' ||
- (args->da_name[1] == '.' && args->da_name[2] == '\0')))
- {
- if (args->da_name[1] == '\0') {
- /*
- * Looking up itself -- return the stored attributes
- * and the proper handle.
- */
- res->dr_status = NFS_OK;
- res->dr_attr = pp->attr;
-
- PrefixToHandle(pp, &res->dr_fhandle);
- } else if (pp->flags & PREFIX_TEMP) {
- /*
- * Want the parent of this sucker. Trim off the
- * last component of the prefix call NameToPrefix
- * to find it.
- *
- * This will only be invoked by the kernel if
- * it encounters .. while in the root vnode of the
- * temporary prefix, at which point it flips to
- * the associated vnode in the root prefix's system
- * to do the lookup, but the handle is still that
- * of the temporary prefix...
- */
- char *cp; /* Start of final component */
- Prefix *ppp; /* Parent Prefix Pointer */
-
- /*
- * Just nuke the final slash...we'll put it back later.
- */
- cp = (char *)rindex(pp->path, '/');
- *cp = '\0'; ppp = NameToPrefix(pp->path); *cp = '/';
-
- /*
- * Set up the return value based on the parent.
- */
- res->dr_status = NFS_OK;
- res->dr_attr = ppp->attr;
-
- PrefixToHandle(ppp, &res->dr_fhandle);
- } else {
- /*
- * Why are you asking me this?
- */
- res->dr_status = NFSERR_NOENT;
- }
- } else if (pp->flags & PREFIX_ROOT) {
- /*
- * Special case -- looking something up in a ROOT
- * prefix causes us to create a new temporary prefix,
- * if one doesn't already exist.
- */
- Prefix *newpp; /* Prefix for component */
-
- /*
- * Form full path for ease of comparison.
- */
- sprintf(path, "%s/%s", pp->path, args->da_name);
- newpp = NameToPrefix(path);
-
- if (newpp == NULL) {
- /*
- * Doesn't exist yet -- create a new Prefix structure
- * for the thing.
- */
- newpp = ImportCreateTempPrefix(path, pp);
- }
-
- /*
- * Set up to answer the query now, returning a
- * standard handle for the prefix.
- */
- res->dr_status = NFS_OK;
- res->dr_attr = newpp->attr;
- PrefixToHandle(newpp, &res->dr_fhandle);
- } else {
- /*
- * Create the LookupToken for the thing and put it on
- * the end of the list of valid tokens.
- */
- struct timeval deltok; /* Interval for nuking */
-
- ltp = ImportAllocLookupToken();
-
- ltp->prefix = pp;
- ltp->name = (char *)malloc(strlen(args->da_name)+1);
- strcpy(ltp->name, args->da_name);
-
- (void)Lst_AtEnd(tokens, (ClientData)ltp);
-
- /*
- * Register an event for deleting the lookup token
- */
- deltok.tv_sec = 10;
- deltok.tv_usec = 0;
- ltp->nukeEvent = Rpc_EventCreate(&deltok, ImportDeleteLookupToken,
- (Rpc_Opaque)ltp);
-
- /*
- * Set up the return filehandle.
- */
- ImportTokenToHandle(ltp, &res->dr_fhandle);
-
- /*
- * Set up the path so we can return an accurate size
- */
- LT_PATH(path, ltp);
-
- /*
- * This is the same as for the GETATTR call... (not
- * sure if the GETATTR support is necessary...)
- */
- res->dr_status = NFS_OK;
- ImportSetLinkAttr(&res->dr_attr, path, pp);
- }
- }
-
- return(SUNRPC_SUCCESS);
- }
-
-
- /***********************************************************************
- * ImportStatFSReq
- ***********************************************************************
- * SYNOPSIS: Handle a STATFS request
- * CALLED BY: SunRpc
- * RETURN: SUNRPC_SUCCESS (bogus statistics are returned to caller)
- * SIDE EFFECTS: None
- *
- * STRATEGY:
- * We don't know the actual parameters for a prefix since we don't
- * know who's serving the thing, nor are we going to find out
- * because of this call (which is issued whenever the prefix is
- * mounted), so we just return that the system is completely full.
- *
- * REVISION HISTORY:
- * Name Date Description
- * ---- ---- -----------
- * ardeb 7/11/89 Initial Revision
- *
- ***********************************************************************/
- static enum clnt_stat
- ImportStatFSReq(remote, msg, args, res, data, resPtr)
- struct sockaddr_in *remote; /* Source of request */
- Rpc_Message msg; /* Message token */
- fhandle_t *args; /* Arguments passed */
- struct nfsstatfs *res; /* Results to return */
- Rpc_Opaque data; /* Data we stored (UNUSED) */
- void **resPtr; /* Room for modified 'res' (UNUSED)*/
- {
- Prefix *pp;
-
- pp = HandleToPrefix(args);
- if (pp == PREFIX_STALE) {
- res->fs_status = NFSERR_STALE;
- } else {
- dprintf("STATFS(%s)\n", pp->path);
-
- bzero(res, sizeof(*res));
-
- /*
- * Return bogus information for the filesystem for now:
- * block and transfer size of 8192 bytes, 1 block in
- * the system and nothing is free...
- */
- res->fs_status = NFS_OK;
- res->fs_tsize = res->fs_bsize = 8192;
- res->fs_blocks = 1;
- res->fs_bfree = 0;
- res->fs_bavail = 0;
-
- }
- return(SUNRPC_SUCCESS);
- }
-
- /***********************************************************************
- * ImportReadDirReq
- ***********************************************************************
- * SYNOPSIS: Handle a READDIR request on a prefix
- * CALLED BY: SunRpc
- * RETURN: SUNRPC_SUCCESS (directory entries are return to the caller)
- * SIDE EFFECTS: None
- *
- * STRATEGY:
- * For most prefixes, this just returns . and ..
- * For a root prefix, however, this returns the list of known
- * subprefixes.
- *
- * The offsets we return (via xdr_putdirres) do no correspond to
- * file positions, as in a real NFS server. Instead, they are the
- * prefix number (i.e. the position in the list).
- *
- * REVISION HISTORY:
- * Name Date Description
- * ---- ---- -----------
- * ardeb 7/11/89 Initial Revision
- *
- ***********************************************************************/
- static enum clnt_stat
- ImportReadDirReq(remote, msg, args, res, data, resPtr)
- struct sockaddr_in *remote; /* Source of request */
- Rpc_Message msg; /* Message token */
- struct nfsrddirargs *args; /* Arguments passed */
- struct nfsrddirres *res; /* Results to return */
- Rpc_Opaque data; /* Data we stored (UNUSED) */
- Rpc_Opaque *resPtr; /* Place holding address of "res". We
- * need to enlarge the thing to hold
- * the directory entries too... */
- {
- Prefix *pp; /* Prefix being read */
- struct direct *dirent; /* All entries */
-
- /*
- * We do this very simply for now, storing all the
- * known entries into a buffer each time, then returning only
- * part of it. I always do brute-force, simplistic solutions
- * on the first pass. Besides, the other buffer will almost
- * always be big enough to hold it, I think, since we tell
- * the thing the FS has a block size of 8k...
- */
- dirent = NULL;
-
- pp = HandleToPrefix(&args->rda_fh);
-
- if (pp == PREFIX_STALE) {
- res->rd_status = NFSERR_STALE;
- } else {
- Prefix *tp; /* Current subprefix being
- * counted or entered */
- int i; /* General counter */
- int total; /* Total number of entries */
- int size; /* General size quantity */
- struct direct d; /* For initial pass... */
- struct direct *dp; /* For subsequent passes... */
-
- dprintf("READDIR(%s): ", pp->path);
-
- /*
- * Count the number of entries available and figure the
- * size of buffer required to hold the entire list. We
- * need to use 'd' because the DIRSIZ macro only operates
- * on a struct direct (silly thing).
- *
- * Note this operation is only valid on a root prefix.
- * In particular, we have to avoid returning anything but
- * . and .. for a temporary prefix. If we don't, performing
- * 'ls -l' of a temporary prefix will cause us to try and
- * mount the prefix for each prefix after it at the same
- * level and each attempt will fail miserably because the
- * node is still locked.
- */
- total = size = 0;
-
- if (pp->flags & PREFIX_ROOT) {
- for (tp = pp->next; tp != NULL; tp=tp->next, total += 1) {
- char *cp = (char *)rindex(tp->path, '/');
-
- d.d_namlen = strlen(cp+1);
- size += DIRSIZ(&d);
- }
- }
-
- /*
- * Add two for . and ..
- */
- d.d_namlen = 1;
- size += DIRSIZ(&d);
-
- d.d_namlen = 2;
- size += DIRSIZ(&d);
-
- total += 2;
-
- dprintf("%d entries requiring %d bytes\n", total, size);
-
- /*
- * Fill in the buffer now. The entries go immediately after the
- * result so the two can be freed at once by the rpc code.
- */
- res = (struct nfsrddirres *)realloc(res,
- sizeof(struct nfsrddirres)+size);
- *resPtr = (Rpc_Opaque)res;
- dirent = (struct direct *)(res+1);
-
- dprintf("\tstoring:");
- /*
- * . comes first
- */
- dp = dirent;
- dp->d_fileno = pp->attr.na_nodeid;
- dp->d_namlen = 1;
- dp->d_name[0] = '.'; dp->d_name[1] = '\0';
- dp->d_reclen = DIRSIZ(dp);
- dp = (struct direct *)((char *)dp + dp->d_reclen);
- dprintf(" .");
-
- /*
- * .. next
- */
- dp->d_fileno = 3; /* BOGUS */
- dp->d_namlen = 2;
- dp->d_name[0] = '.'; dp->d_name[1] = '.';
- dp->d_name[2] = '\0';
- dp->d_reclen = DIRSIZ(dp);
- dp = (struct direct *)((char *)dp + dp->d_reclen);
- dprintf(" ..");
-
- /*
- * Now the rest of the entries
- */
- if (pp->flags & PREFIX_ROOT) {
- for (tp = pp->next; tp != NULL; tp = tp->next, i++){
- char *cp = (char *)rindex(tp->path, '/');
-
- dp->d_fileno = tp->attr.na_nodeid;
- dp->d_namlen = strlen(cp+1);
- strcpy(dp->d_name, cp+1);
- dp->d_reclen = DIRSIZ(dp);
- dp = (struct direct *)((char *)dp + dp->d_reclen);
- dprintf(" %s", cp+1);
- }
- }
-
- dprintf("\n");
- /*
- * Find the start for the return value
- */
-
- dp = dirent;
- if (args->rda_offset < total) {
- dprintf("\tstarting at %d (skipping:", args->rda_offset);
- for (i = args->rda_offset; i > 0; i--) {
- dprintf(" %s", dp->d_name);
- dp = (struct direct *)((char *)dp + dp->d_reclen);
- }
- dprintf(")\n");
- } else {
- dprintf("\tread offset (%d) beyond range\n",
- args->rda_offset);
- }
- res->rd_entries = dp;
-
- /*
- * Skip over all those entries that will fit.
- * res->rd_offset starts out at the index of the first
- * entry being returned. xdr_putrddirres will up this
- * for each record encoded so it can deal with us
- * screwing up (not that we would, but better save than
- * sorry).
- */
- res->rd_offset = args->rda_offset;
- dprintf("\treturning:");
- for (size = args->rda_count, i = args->rda_offset;
- i < total;
- i++)
- {
- if ((size -= DIRSIZ(dp)) >= 0) {
- dprintf(" %s", dp->d_name);
- dp = (struct direct *)((char *)dp + dp->d_reclen);
- } else {
- break;
- }
- }
-
- /*
- * Set the final fields of the result, transferring
- * the buffer size from the args to the result for
- * xdr_putrddirres->
- */
- res->rd_bufsize = args->rda_count;
- res->rd_eof = (i == total);
- res->rd_size = (char *)dp - (char *)res->rd_entries;
- res->rd_status = NFS_OK;
- dprintf("\n\t%d bytes total, eof = %s, offset = %d\n",
- res->rd_size, res->rd_eof ? "true" : "false",
- res->rd_offset);
- }
-
- return(SUNRPC_SUCCESS);
- }
-
- /******************************************************************************
- *
- * EXPORTED UTILITIES
- *
- *****************************************************************************/
-
- /***********************************************************************
- * Import_MountPrefix
- ***********************************************************************
- * SYNOPSIS: Mount a prefix directory from ourselves. The prefix
- * should have been checked for locks
- * CALLED BY: ImportPrefix, ImportPrefixTree, MountUnmountPrefix
- * RETURN: 1 if successful
- * SIDE EFFECTS: The Prefix is remounted
- *
- * STRATEGY:
- *
- * REVISION HISTORY:
- * Name Date Description
- * ---- ---- -----------
- * ardeb 7/ 6/89 Initial Revision
- *
- ***********************************************************************/
- int
- Import_MountPrefix(pp)
- Prefix *pp; /* Prefix to remount */
- {
- if (Lst_Member(prefixes, (ClientData)pp) == NILLNODE) {
- (void)Lst_AtEnd(prefixes, (ClientData)pp);
- }
- return (Child_Call(pp, PREFIX_MOUNT_LOCAL));
- }
-
- /***********************************************************************
- * Import_CreatePrefix
- ***********************************************************************
- * SYNOPSIS: Create a Prefix structure for a prefix
- * CALLED BY: main, ImportPrefix, ImportPrefixTree
- * RETURN: Nothing
- * SIDE EFFECTS: The Prefix * is added to the prefixes list
- *
- * STRATEGY:
- *
- * REVISION HISTORY:
- * Name Date Description
- * ---- ---- -----------
- * ardeb 7/ 7/89 Initial Revision
- *
- ***********************************************************************/
- Prefix *
- Import_CreatePrefix(path)
- char *path; /* Path of prefix (COPIED) */
- {
- Prefix *pp; /* New prefix */
- struct stat stb; /* State of underlying directory, for conversion
- * into prefix's stored attributes */
-
- if (path[0] != '/') {
- Message("prefix \"%s\" invalid -- must be absolute\n", path);
- return((Prefix *)NULL);
- }
-
- pp = AllocPrefix();
- pp->path = (char *)malloc(strlen(path) + 1);
- strcpy(pp->path, path);
-
- if (stat(pp->path, &stb) < 0) {
- perror(pp->path);
- free(pp->path);
- FreePrefix(pp);
- pp = (Prefix *)NULL;
- } else {
- /*
- * Convert the stat structure into an nfs attributes one. Prefixes
- * always appear to be read-only directories until they are mounted.
- * They take on the attributes of their underlying directory.
- */
- pp->attr.na_type = NFDIR;
- pp->attr.na_mode = 0555 | S_IFDIR;
- pp->attr.na_nlink = 1;
- pp->attr.na_uid = stb.st_uid;
- pp->attr.na_gid = stb.st_gid;
- pp->attr.na_size = stb.st_size;
- pp->attr.na_blocksize = stb.st_blksize;
- pp->attr.na_rdev = -1;
- pp->attr.na_blocks = stb.st_blocks;
- pp->attr.na_fsid = -1;
- pp->attr.na_nodeid = stb.st_ino;
- pp->attr.na_atime.tv_sec = stb.st_atime;
- pp->attr.na_atime.tv_usec = stb.st_spare1;
- pp->attr.na_mtime.tv_sec = stb.st_mtime;
- pp->attr.na_mtime.tv_usec = stb.st_spare2;
- pp->attr.na_ctime.tv_sec = stb.st_ctime;
- pp->attr.na_ctime.tv_usec = stb.st_spare3;
-
- dprintf("importing %s\n", pp->path);
-
- pp->flags = 0;
- pp->locks = 0;
- pp->unmount = (Rpc_Event)NULL;
- pp->next = (Prefix *)NULL;
- pp->serverName = pp->remote = (char *)NULL;
- pp->options = "rw";
-
- (void)Lst_AtEnd(prefixes, (ClientData)pp);
- }
-
- return(pp);
- }
-
- /***********************************************************************
- * ImportDeleteTemp
- ***********************************************************************
- * SYNOPSIS: Delete a temporary prefix.
- * CALLED BY: ImportDelete, Rpc_Event (set up by Mount_Unmount)
- * RETURN: 0
- * SIDE EFFECTS: The prefix is removed from the prefixes list and that
- * of its parent root prefix.
- *
- * STRATEGY:
- *
- * REVISION HISTORY:
- * Name Date Description
- * ---- ---- -----------
- * ardeb 9/10/89 Initial Revision
- *
- ***********************************************************************/
- static int
- ImportDeleteTemp(pp)
- Prefix *pp;
- {
- Prefix **prev; /* For traversal... */
- Prefix *tp;
- char *cp;
- LstNode ln;
-
- if (PrefixIsLocked(pp)) {
- Message("Trying to delete temp prefix %s, but it's locked %d time%s",
- pp->path, pp->locks, pp->locks > 1 ? "s" : "");
- return(0);
- }
-
- /*
- * Strip off the final component of the doomed prefix's path and find
- * the corresponding prefix, which is its parent.
- */
- cp = (char *)rindex(pp->path, '/');
- /*
- * %%% ERROR CHECK %%%
- */
- if (cp == NULL) {
- Message("No / in temp prefix's path '%s'. What the f*** is going on?\n",
- pp->path);
- return(0);
- }
-
- *cp = '\0';
- tp = NameToPrefix(pp->path);
-
- /*
- * %%% ERROR CHECK %%%
- */
- if (tp == NULL) {
- *cp = '/';
- Message("Couldn't find root for temp prefix %s\n",
- pp->path);
- #ifdef MEM_TRACE
- if (malloc_size(pp->path) > strlen(pp->path)+1) {
- cp = pp->path + strlen(pp->path);
- Message("\tremaining bytes in block = \"%.*s\"\n",
- (pp->path + malloc_size(pp->path))-cp, cp);
- }
- #endif
- return (0);
- }
-
- /*
- * Invalidate any lookup tokens pending for this prefix.
- */
- for (ln = Lst_First(tokens); ln != NILLNODE;) {
- LookupToken *ltp = (LookupToken *)Lst_Datum(ln);
-
- ln = Lst_Succ(ln);
-
- if (ltp->prefix == pp) {
- ImportDeleteLookupToken(ltp, ltp->nukeEvent);
- }
- }
-
- /*
- * Find the prefix in the subprefix list for the root, keeping
- * track of the place where the pointer to the current node is
- * stored so the prefix can be removed once it's found.
- */
- for (prev = &tp->next, tp = tp->next; tp != pp; tp = *prev) {
- prev = &tp->next;
- }
-
- /*
- * Remove the prefix from the chain...
- */
- *prev = pp->next;
-
- /*
- * Free up the prefix's storage. Since it's not mounted, this
- * only involves the freeing of the path and the structure itself.
- */
- free(pp->path);
- FreePrefix(pp);
-
- return(0);
- }
- /******************************************************************************
- *
- * CUSTOMS-RPC SERVERS
- *
- *****************************************************************************/
-
-
- /***********************************************************************
- * ImportCommon
- ***********************************************************************
- * SYNOPSIS: Import a root or regular prefix
- * CALLED BY: ImportPrefix, ImportPrefixRoot
- * RETURN: Nothing
- * SIDE EFFECTS: Another Prefix may be added to the list.
- *
- * STRATEGY:
- *
- * REVISION HISTORY:
- * Name Date Description
- * ---- ---- -----------
- * ardeb 10/ 6/89 Initial Revision
- *
- ***********************************************************************/
- static void
- ImportCommon(msg, path, flags)
- Rpc_Message msg; /* Message for reply/error */
- char *path; /* Prefix to import */
- int flags; /* Initial flags for prefix */
- {
- Prefix *pp; /* New prefix structure */
-
- /*
- * Make sure we're not duplicating an existing prefix. The only time
- * we allow this is when the user is converting a temporary prefix
- * to a permanent one (not sure why, but can't see any reason to disallow
- * it...)
- */
- pp = NameToPrefix(path);
- if (pp != NULL) {
- if (PrefixIsLocked(pp)) {
- Rpc_Error(msg, PREFIX_LOCKED);
- }
-
- PrefixLock(pp);
- if (pp->flags & PREFIX_TEMP) {
- /*
- * Converting a temporary prefix into a real one. If thing is
- * mounted remotely, we've nothing else to do -- when the
- * thing finally gets unmounted, it will be remounted on
- * us automatically. Otherwise, try and mount the thing on
- * ourselves.
- */
- pp->flags &= ~PREFIX_TEMP;
- pp->flags |= flags;
- if ((pp->flags & PREFIX_MOUNTED) || Import_MountPrefix(pp)) {
- Rpc_Return(msg, 0, NULL);
- } else {
- /*
- * Failure. I'm so ashamed. Make the prefix temporary again
- * and return a system error.
- */
- pp->flags |= PREFIX_TEMP;
- pp->flags &= ~flags;
- Rpc_Error(msg, RPC_SYSTEMERR);
- }
- } else {
- Rpc_Error(msg, DUPLICATE_PREFIX);
- }
- PrefixUnlock(pp);
- } else {
- pp = Import_CreatePrefix(path);
-
- if (pp == NULL) {
- Rpc_Error(msg, RPC_BADARGS);
- } else {
- /*
- * Set initial flags.
- */
- pp->flags = flags;
-
- /*
- * Mount the thing on ourselves
- */
- if (Import_MountPrefix(pp)) {
- /*
- * All ok -- return now.
- */
- Rpc_Return(msg, 0, NULL);
- } else {
- Rpc_Error(msg, RPC_SYSTEMERR);
- }
- }
- }
- }
-
- /***********************************************************************
- * ImportPrefix
- ***********************************************************************
- * SYNOPSIS: Import another prefix
- * CALLED BY: PREFIX_IMPORT
- * RETURN: Nothing
- * SIDE EFFECTS: Another Prefix is added to the prefixes list
- *
- * STRATEGY:
- *
- * REVISION HISTORY:
- * Name Date Description
- * ---- ---- -----------
- * ardeb 7/ 7/89 Initial Revision
- *
- ***********************************************************************/
- static void
- ImportPrefix(from, msg, len, data, serverData)
- struct sockaddr_in *from; /* Source of message */
- Rpc_Message msg; /* Mesage for reply/error */
- int len; /* Length of passed data (includes
- * null byte at end of prefix) */
- Rpc_Opaque data; /* Name of prefix (null-terminated) */
- Rpc_Opaque serverData; /* Data we gave (UNUSED) */
- {
- ImportCommon(msg, (char *)data, 0);
- }
-
-
- /***********************************************************************
- * ImportPrefixRoot
- ***********************************************************************
- * SYNOPSIS: Import a tree of prefixes
- * CALLED BY: PREFIX_IMPORT_ROOT
- * RETURN: Nothing
- * SIDE EFFECTS: Another Prefix is added to the prefixes list
- *
- * STRATEGY:
- *
- * REVISION HISTORY:
- * Name Date Description
- * ---- ---- -----------
- * ardeb 7/ 7/89 Initial Revision
- *
- ***********************************************************************/
- static void
- ImportPrefixRoot(from, msg, len, data, serverData)
- struct sockaddr_in *from; /* Source of message */
- Rpc_Message msg; /* Message for reply/error */
- int len; /* Length of passed data (includes
- * null byte at end of prefix) */
- Rpc_Opaque data; /* Name of prefix (null-terminated) */
- Rpc_Opaque serverData; /* Data we gave (UNUSED) */
- {
- ImportCommon(msg, (char *)data, PREFIX_ROOT);
- }
-
- /***********************************************************************
- * ImportDelete
- ***********************************************************************
- * SYNOPSIS: Delete a prefix.
- * CALLED BY: PREFIX_DELETE
- * RETURN: Nothing
- * SIDE EFFECTS: If the prefix is a root prefix and it has mounted
- * subprefixes, the subprefixes are deleted too.
- *
- * STRATEGY:
- * - Locate prefix
- * - If no such thing, pass the buck to the Export module
- * - If we need to unmount the thing, fork and do so
- * - Else if the prefix is temporary, delete it.
- *
- * REVISION HISTORY:
- * Name Date Description
- * ---- ---- -----------
- * ardeb 7/ 8/89 Initial Revision
- *
- ***********************************************************************/
- static void
- ImportDelete(from, msg, len, data, serverData)
- struct sockaddr_in *from; /* Source of data */
- Rpc_Message msg; /* Message for reply/return */
- int len; /* Length of prefix (including null) */
- Rpc_Opaque data; /* Null-terminated prefix */
- Rpc_Opaque serverData; /* Data we gave (UNUSED) */
- {
- LstNode ln;
- Prefix *pp;
- char *answer;
-
- pp = NameToPrefix((char *)data);
-
- if (pp == NULL) {
- /*
- * No such prefix -- complain.
- */
- answer = "no such prefix imported";
- goto ret;
- }
-
- if (PrefixIsLocked(pp)) {
- answer = "prefix is locked";
- goto ret;
- }
-
- answer = "Ok";
- /*
- * The case of an unmounted temporary prefix is special -- we need to
- * remove the thing not only from the prefixes list, but also from
- * its siblings in the subprefix list of its parent.
- *
- * For everything else, we need to unmount the thing from somewhere,
- * be it ourselves or its remote system.
- *
- * Note that the deletion of a mounted, temporary prefix is also special:
- * it takes two deletions to get rid of it.
- */
- if (((pp->flags & PREFIX_TEMP) == 0) || (pp->flags & PREFIX_MOUNTED))
- {
- if (pp->flags & PREFIX_ROOT) {
- /*
- * If the node's a root, attempt to unmount all its
- * subprefixes.
- */
- Prefix *tp;
-
- for (tp = pp->next; tp != NULL; tp = tp->next) {
- if ((tp->flags & PREFIX_MOUNTED) &&
- (!Mount_Unmount(tp, &answer)))
- {
- /*
- * Couldn't unmount subprefix, so can't unmount
- * top-level.
- */
- goto ret;
- }
- }
- }
-
- /*
- * Try and unmount the prefix itself.
- */
- if (pp->flags & PREFIX_MOUNTED) {
- if (!Mount_Unmount(pp, &answer)) {
- goto ret;
- }
- } else {
- /*
- * Can't be temporary, so must have been mounted on ourselves.
- */
- if (!Child_Call(pp, PREFIX_UNMOUNT_LOCAL)) {
- answer = "Couldn't unmount from myself?";
- goto ret;
- }
- }
- if (!(pp->flags & PREFIX_TEMP)) {
- /*
- * Now nuke the Prefix descriptor(s) since everything's
- * disengaged, blowing away this prefix and all its
- * subprefixes. This works for non-roots too, since
- * prefixes have their 'next' field initialized to NULL.
- */
- while (pp != NULL) {
- Prefix *next = pp->next;
-
- /*
- * Nuke any lookup tokens pending for the prefix.
- */
- for (ln = Lst_First(tokens); ln != NILLNODE; ) {
- LookupToken *ltp = (LookupToken *)Lst_Datum(ln);
-
- ln = Lst_Succ(ln);
- if (ltp->prefix == pp) {
- ImportDeleteLookupToken(ltp, ltp->nukeEvent);
- }
- }
-
- free(pp->path);
- FreePrefix(pp);
-
- pp = next;
- }
- }
- } else if (pp->flags & PREFIX_TEMP) {
- (void)ImportDeleteTemp(pp);
- }
-
- ret:
- Rpc_Return(msg, strlen(answer)+1, (Rpc_Opaque)answer);
- }
-
- /***********************************************************************
- * ImportUnmount
- ***********************************************************************
- * SYNOPSIS: Handle a PREFIX_UNMOUNT call from a server that's
- * deleting an exported prefix.
- * CALLED BY: PREFIX_UNMOUNT
- * RETURN: An empty reply if couldn't unmount.
- * SIDE EFFECTS: The serverName and remote fields are nulled and the
- * remote system unmounted.
- *
- * STRATEGY:
- * A lot like PREFIX_DELETE, except the prefix isn't deleted and
- * a return value is only sent if there's an error.
- *
- * REVISION HISTORY:
- * Name Date Description
- * ---- ---- -----------
- * ardeb 7/11/89 Initial Revision
- *
- ***********************************************************************/
- static void
- ImportUnmount(from, msg, len, data, serverData)
- struct sockaddr_in *from; /* Source of message */
- Rpc_Message msg; /* Message for reply/error */
- int len; /* Length of parameters */
- Rpc_Opaque data; /* Parameters (prefix name) */
- Rpc_Opaque serverData; /* Data we gave (UNUSED) */
- {
- if (ntohs(from->sin_port) != PREFIX_PORT) {
- Rpc_Error(msg, RPC_ACCESS);
- } else {
- LstNode ln;
-
- for (ln = Lst_First(prefixes); ln != NILLNODE; ln = Lst_Succ(ln)) {
- Prefix *pp;
-
- pp = (Prefix *)Lst_Datum(ln);
-
- if ((strcmp(pp->path, (char *)data) == 0) &&
- (pp->serverName != NULL) &&
- (pp->server.sin_addr.s_addr == from->sin_addr.s_addr))
- {
- char *answer; /* JUNK */
-
- if (PrefixIsLocked(pp)) {
- /*
- * If prefix in flux, we can't unmount it.
- */
- Rpc_Return(msg, 0, (Rpc_Opaque)NULL);
- } else if (pp->flags & PREFIX_MOUNTED) {
- if (!Mount_Unmount(pp, &answer)) {
- /*
- * Couldn't unmount -- let the server know
- */
- struct hostent *he;
-
- Rpc_Return(msg, 0, (Rpc_Opaque)NULL);
-
- /*
- * Now tell people to stop using the thing.
- */
- he = gethostbyaddr(&from->sin_addr,
- sizeof(from->sin_addr),
- AF_INET);
- Message("Warning: %s trying to delete %s.",
- he ? he->h_name : InetNtoA(from->sin_addr),
- pp->path);
- Message("Please stop using its files");
- } else if (!(pp->flags & PREFIX_TEMP)) {
- /*
- * Remount on ourselves if not temporary.
- */
- Import_MountPrefix(pp);
- }
- } else {
- /*
- * Must have been "linked" to something else.
- * Just clear out the serverName and remote fields.
- */
- free(pp->serverName); free(pp->remote);
- pp->serverName = pp->remote = (char *)NULL;
- }
- break;
- }
- }
- }
- }
-
-
-
- /***********************************************************************
- * Import_Init
- ***********************************************************************
- * SYNOPSIS: Initialize this here module.
- * CALLED BY: main
- * RETURN: Nothing
- * SIDE EFFECTS: The "tokens" list is created
- *
- * STRATEGY:
- *
- * REVISION HISTORY:
- * Name Date Description
- * ---- ---- -----------
- * ardeb 7/ 6/89 Initial Revision
- *
- ***********************************************************************/
- void
- Import_Init()
- {
- int addrlen;
-
- tokens = Lst_Init(FALSE);
- freeTokens = Lst_Init(FALSE);
-
- /*
- * Create the socket over which we will field the kernel's requests for
- * prefixes.
- */
- prefixSvc = Rpc_UdpCreate(True, 0);
- /*
- * Fetch the name of the socket so we can pass it to the kernel.
- * Actually, we don't really fetch the address. We just tell the kernel
- * to use its software loopback stuff. No point in routing the thing,
- * is there?
- */
- addrlen = sizeof(prefixMountAddr);
- if (getsockname(prefixSvc, &prefixMountAddr, &addrlen) < 0) {
- perror("getsockname:prefixSvc");
- exit(0);
- }
- prefixMountAddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- prefixMountAddr.sin_family = AF_INET;
-
- /*
- * Register the Sun RPC servers for the socket. These are the only
- * NFS procedures we handle -- anything else generates a "procedure
- * unavailable" error.
- */
- SunRpc_ServerCreate(prefixSvc, NFS_PROGRAM, RFS_NULL, NFS_VERSION,
- ImportNullReq, (Rpc_Opaque)NULL,
- 0, xdr_void, 0, xdr_void);
-
- SunRpc_ServerCreate(prefixSvc, NFS_PROGRAM, RFS_GETATTR, NFS_VERSION,
- ImportGetAttrReq, (Rpc_Opaque)NULL,
- sizeof(fhandle_t), xdr_fhandle,
- sizeof(struct nfsattrstat), xdr_attrstat);
-
- SunRpc_ServerCreate(prefixSvc, NFS_PROGRAM, RFS_READLINK, NFS_VERSION,
- ImportReadLinkReq, (Rpc_Opaque)NULL,
- sizeof(fhandle_t), xdr_fhandle,
- sizeof(struct nfsrdlnres), xdr_rdlnres);
-
- SunRpc_ServerCreate(prefixSvc, NFS_PROGRAM, RFS_LOOKUP, NFS_VERSION,
- ImportLookupReq, (Rpc_Opaque)NULL,
- sizeof(struct nfsdiropargs), xdr_diropargs,
- sizeof(struct nfsdiropres), xdr_diropres);
-
- SunRpc_ServerCreate(prefixSvc, NFS_PROGRAM, RFS_STATFS, NFS_VERSION,
- ImportStatFSReq, (Rpc_Opaque)NULL,
- sizeof(fhandle_t), xdr_fhandle,
- sizeof(struct nfsstatfs), xdr_statfs);
-
- SunRpc_ServerCreate(prefixSvc, NFS_PROGRAM, RFS_READDIR, NFS_VERSION,
- ImportReadDirReq, (Rpc_Opaque)NULL,
- sizeof(struct nfsrddirargs), xdr_rddirargs,
- sizeof (struct nfsrddirres), xdr_putrddirres);
-
- Rpc_ServerCreate(prefixSock, PREFIX_IMPORT, ImportPrefix, NULL, NULL,
- NULL);
- Rpc_ServerCreate(prefixSock, PREFIX_IMPORT_ROOT, ImportPrefixRoot,
- NULL, NULL, NULL);
- Rpc_ServerCreate(prefixSock, PREFIX_DELETE, ImportDelete, NULL, NULL,
- NULL);
- Rpc_ServerCreate(prefixSock, PREFIX_UNMOUNT, ImportUnmount, NULL, NULL,
- NULL);
-
- }
-